/**
 ** NuString
 ** Provides a set of useful string manipulation
 ** procedures.
 **/

#import "NuString.h"
#import <strings.h>
#import <stdlib.h>

// here are the "good" malloc lengths.  Anything larger than
// 4088 is best is a multiple of 8192
int goodLens[] = {16, 32, 64, 128, 176,
     252, 340, 508, 680, 1020, 1360, 2044, 2724, 4088} ;


int bestLength_(int len)
{ // return the "best" malloc size, given length
  // of a string (len should include space for
  // the null terminator).
  int theLen, i ;
  if(len <= 4088)
  { i = 0 ;
    while(goodLens[i] < len)
	i++ ;
    return goodLens[i] ;
  }
  else
  { i = 1 ;
    while((theLen = (i * 8192)) < len)
      i++ ;
    return theLen ;
  }
}

@implementation NuString: Object
{ char *string ;
  unsigned capacity ;
}


+ new: (char *) aString ;
{ // as a convenience, alloc and init from a cstring
  self = [[self alloc] initFromString: aString] ;
  return self ;
}


- catStream: (NXStream *) aStream ;
{ // concatenate aStream onto myself
  int neededLength, currentLength, streamLength, maxLength ;
  char *streamBuffer ;
  NXGetMemoryBuffer(aStream, &streamBuffer, &streamLength, &maxLength);
  currentLength = strlen(string) ;
  neededLength =  currentLength + streamLength + 1 ;
  if(neededLength > capacity)
  { char *newString ;
    capacity = bestLength_(neededLength) ;
    newString = (char *) malloc(capacity) ;
    strcpy(newString,string);
    free(string) ;
    string = newString ;
  }
  bcopy(streamBuffer,&string[currentLength],streamLength) ;
  string[neededLength -1] = '\0' ;
  return self ;
}    
  
- catString: (char *) aString ;
{ // concatenate aString onto myself
  int neededLength ;
  neededLength =  strlen(string) + strlen(aString) + 1 ;
  if(neededLength > capacity)
  { char *newString ;
    capacity = bestLength_(neededLength) ;
    newString = (char *) malloc(capacity) ;
    strcpy(newString,string);
    free(string) ;
    string = newString ;
  }
  strcat(string, aString) ;
  return self ;
}   
 
- (const char *) cString ;
{ // returns the "address" of the string
  return (const char *) string ;
}

  
- free ;
{  if(string)
     free(string) ;
  return [super free] ;
}


- initFromStream: (NXStream *) aStream ;
{ char *buffer ;
  int length, maxLength ;
  NXGetMemoryBuffer(aStream, &buffer, &length, &maxLength);
  capacity = bestLength_(length + 1) ;
  string = (char *) malloc(capacity) ;
  bcopy(buffer, string, length);
  string[length] = '\0' ; // make sure null-terminated!
  return self ;
}

- initFromString: (char *) aString ;
{ capacity = bestLength_(strlen(aString) + 1) ;
  string = (char *) malloc(capacity) ;
  strcpy(string,aString) ;
  return self ;
} 

-read: (NXTypedStream *) stream ;
{ [super read: stream] ;
  NXReadTypes(stream, "*i", &string, &capacity) ;
  return self ;
}

-write: (NXTypedStream *) stream ;
{ [super write: stream] ;
  NXWriteTypes(stream, "*i", &string, &capacity)  ;
  return self ;
}

@end
 